/*
 * SyncResource.java
 *
 * Created on April 12, 2007, 1:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.auth.service.app;

import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.client.XMLEntity;
import org.atomojo.app.client.XMLRepresentationParser;
import org.atomojo.auth.service.db.AuthDB;
import org.atomojo.auth.service.db.Realm;
import org.atomojo.auth.service.db.RealmUser;
import org.atomojo.auth.service.db.User;
import org.atomojo.auth.service.db.XML;
import org.infoset.xml.util.DocumentDestination;
import org.restlet.Request;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;

/**
 *
 * @author alex
 */
public class UserRecoveryResource extends ServerResource
{
   
   long expiration = 3600*1000;
   AuthDB db;
   Realm realm;
   String email;
   String alias;
   String session;
   /** Creates a new instance of SyncResource */
   public UserRecoveryResource() {
      setNegotiated(false);
   }

   protected void doInit() {
      db = (AuthDB)getRequest().getAttributes().get(AuthApplication.DB_ATTR);
      realm = (Realm)getRequest().getAttributes().get(AuthApplication.REALM_ATTR);
      email = AuthApplication.getStringAttribute(getRequest(),"email",null);
      alias = AuthApplication.getStringAttribute(getRequest(),"alias",null);
      session = AuthApplication.getStringAttribute(getRequest(),"session",null);
   }
   
   Representation getSessionEntity(RealmUser user,UUID session)
   {
      String email = user.getEmail();
      if (email==null) {
         return new StringRepresentation(
             "<session xmlns='"+XML.authNS+"' id='"+session+"' user-id='"+user.getUser().getUUID()+"' user-alias='"+user.getAlias()+"'/>",
             MediaType.APPLICATION_XML
         );
      } else {
         return new StringRepresentation(
             "<session xmlns='"+XML.authNS+"' id='"+session+"' user-id='"+user.getUser().getUUID()+"' user-alias='"+user.getAlias()+"'><email>"+XMLEntity.escape(email)+"</email></session>",
             MediaType.APPLICATION_XML
         );
      }
   }
   
   public Representation get()
   {
      if (session!=null) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return null;
      }
      if (realm==null) {
         return null;
      }
      //getContext().getLogger().info("Testing auth...");
      try {
         RealmUser user = null;
         if (email!=null) {
            getLogger().info("Recovery requested for realm "+realm.getName()+" email "+email);
            user = db.findRealmUserByEmail(realm, email);
         } else {
            getLogger().info("Recovery requested for realm "+realm.getName()+" alias "+alias);
            user = db.getRealmUser(realm,alias);
         }
         if (user==null) {
            return null;
         }
         User.Authenticated authd = user.getUser().recover(realm);
         return getSessionEntity(user,authd.getSession());
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get user data from database.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      } catch (NoSuchAlgorithmException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get encrypt user password",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Encryption algorithm error, see logs.");
      }
   }
   
   public Representation delete() {
      if (session==null) {
         getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
         return null;
      }
      try {
         UUID usession = UUID.fromString(session);
         db.expireSession(usession);
         getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
         return null;
      } catch (IllegalArgumentException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return null;
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot delete session "+session+" from database.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      }
   }
   
   public Representation post(Representation entity)
   {
      if (session==null) {
         getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
         return null;
      }
      if (!XMLRepresentationParser.isXML(entity.getMediaType())) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Non-XML media type for entity body: "+entity.getMediaType().getName());
      }
      
      XMLRepresentationParser postParser = XML.createParser();
      postParser.addAllowedElement(XML.PASSWORD_NAME);
      
      String password = null;
      try {
         DocumentDestination dest = new DocumentDestination();
         postParser.parse(entity,dest);
         password = dest.getDocument().getDocumentElement().getText();
      } catch (Exception ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("XML parse error: "+ex.getMessage());
      }
      
      if (password==null) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("No password.");
      }
      password = password.trim();
      if (password.length()==0) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Password is empty.");
      }
      try {
         UUID usession = UUID.fromString(session);
         User.Authenticated authd = db.isAuthenticated(realm, usession);
         if (authd==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_GONE);
            return null;
         } else {
            authd.getUser().setPassword(password);
            getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
            return null;
         }
      } catch (NoSuchAlgorithmException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot encrypt password.",ex);
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Password encryption error.");
      } catch (IllegalArgumentException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Bad UUID value: "+session);
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get session "+session+" from database.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      }
   }
   
  
}
